const fs = require("fs-extra");
const handlebars = require("handlebars");
const { resolve } = require("path");

const getTplFilePath = (meta) => ({
  // docs 目录
  readme: {
    from: "./makeTemplate/docs/README.md.tpl",
    to: `../../packages/${meta.compName}/docs/README.md`,
  },
  basic: {
    from: "./makeTemplate/docs/basic.vue.tpl",
    to: `../../packages/${meta.compName}/docs/basic.vue`,
  },
  // src 目录
  vue: {
    from: "./makeTemplate/src/index.vue.tpl",
    to: `../../packages/${meta.compName}/src/index.vue`,
  },
  // 根目录
  install: {
    from: "./makeTemplate/index.ts.tpl",
    to: `../../packages/${meta.compName}/index.ts`,
  },
});

const compFilesTplReplacer = (meta) => {
  const filePaths = getTplFilePath(meta);
  Object.keys(filePaths).forEach((key) => {
    // readFileSync() 同步读取文件  参数： 1. 文件路径  2. 编码格式
    /**
     * path.resolve([...paths]) 将方法路径或路径片段的序列解析为绝对路径
     * 从右到左处理，逐次添加到前面
     * 若没传入path片段，返回当前工作目录的绝对路径
     */
    // __dirname ： 全局变量，获得当前目录的全路径
    const fileTpl = fs.readFileSync(
      resolve(__dirname, filePaths[key].from),
      "utf-8"
    );
    // handlebars.compile(template) 编译模板,以便可以立即执行，方法返回一个函数，数据以参数形式传入
    const fileContent = handlebars.compile(fileTpl)(meta);
    /**
     *  fs.outputFile(file,data,options,callback)  将数据写入给定文件，若问文件目录，则自动创建
     *  file: 写入文件的路径
     *  data: 写入文件的字符串
     *  options: 指定可选参数的字符串或对象
     */
    fs.outputFile(resolve(__dirname, filePaths[key].to), fileContent, (err) => {
      if (err) console.log(err);
    });
  });
};

// 读取packages/list.json 并更新
const listJsonTplReplacer = (meta) => {
  const listFilePath = "../../packages/list.json";
  const listFileTpl = fs.readFileSync(
    resolve(__dirname, listFilePath),
    "utf-8"
  );
  const listFileContent = JSON.parse(listFileTpl);
  listFileContent.push(meta);
  const newListFileContentFile = JSON.stringify(listFileContent, null, 2);
  fs.writeFile(
    resolve(__dirname, listFilePath),
    newListFileContentFile,
    (err) => {
      if (err) console.log(err);
    }
  );
  return listFileContent;
};

// 更新router.ts
const routerTplReplacer = (listFileContent) => {
  const routerFileFrom = "./makeTemplate/router.ts.tpl";
  const routerFileTo = "../../src/router.ts";
  const routerFileTpl = fs.readFileSync(
    resolve(__dirname, routerFileFrom),
    "utf-8"
  );
  const routerMeta = {
    routes: listFileContent.map((comp) => {
      return `{
        title: '${comp.compZhName}',
        name:'${comp.compName}',
        path:'/components/${comp.compName}',
        component:() => import('packages/${comp.compName}/docs/README.md')
      }`;
    }),
  };
  const routerFileContent = handlebars.compile(routerFileTpl, {
    noEscape: true,
  })(routerMeta);
  fs.outputFile(resolve(__dirname, routerFileTo), routerFileContent, (err) => {
    if (err) console.log(err);
  });
};

// 更新 install.ts
const installTsTplReplacer = (listFileContent) => {
  // 设置输入输出路径
  const installFileFrom = "./makeTemplate/install.ts.tpl";
  const installFileTo = "../../packages/index.ts";

  // 读取模板内容
  const installFileTpl = fs.readFileSync(
    resolve(__dirname, installFileFrom),
    "utf-8"
  );

  // 根据传入的信息构造数据
  const installMeta = {
    importPlugins: listFileContent
      .map(({ compName }) => `import {${compName}Plugin} from './${compName}';`)
      .join("\n"),
    installPlugins: listFileContent
      .map(({ compName }) => `${compName}Plugin.install?.(app);`)
      .join("\n"),
    exportPlugins: listFileContent
      .map(({ compName }) => `export * from './${compName}'`)
      .join("\n"),
  };

  // 使用handlebars 替换模板内容
  const installFileContent = handlebars.compile(installFileTpl, {
    noEscape: true,
  })(installMeta);

  // 渲染模板并输出至指定目录
  fs.outputFile(
    resolve(__dirname, installFileTo),
    installFileContent,
    (err) => {
      if (err) console.log(err);
    }
  );
};

module.exports = (meta) => {
  compFilesTplReplacer(meta);
  const listFileContent = listJsonTplReplacer(meta);
  routerTplReplacer(listFileContent);
  installTsTplReplacer(listFileContent);

  console.log(`组件新建完毕，请前往 packages/${meta.compName} 目录进行开发`);
};
